/*	Copyright 2007 - Xavier Baro (xbaro@cvc.uab.cat)

	This file is part of eapmlib.

    Eapmlib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or any 
	later version.

    Eapmlib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "XMLOpenCV.h"
#include <fstream>
#include <iostream>

using namespace std;

Evolutive::CXMLOpenCV::CXMLOpenCV(void)
{	
#ifndef USE_OPENCV
	OPENCV_ERROR_CLASS("CXMLOpenCV");
#endif
}

Evolutive::CXMLOpenCV::~CXMLOpenCV(void)
{	
}
#ifdef USE_OPENCV
void Evolutive::CXMLOpenCV::ExportClassifier(CCascade* Classifier,string FileName,string Name)
{
	fstream ofs;
	string ExpectedClass="CCascade";

	//! Verify the classifier
	if(!Classifier)
		throw CEvolutiveLibException("NULL pointer",__FILE__,__LINE__,"ExportClassifier");

	//! Verify the type of the class
	if(ExpectedClass.compare(Classifier->GetClassNameID()))
		throw CEvolutiveLibException("Incorrect class type",__FILE__,__LINE__,"ExportClassifier");
	
	//! Create the output file
	ofs.open(FileName.data(),ios_base::out | ios_base::trunc);
	if(ofs.fail())
		throw CEvolutiveLibException("Cannot open output file",__FILE__,__LINE__,"ExportClassifier");

	//! Open the XML header
	ofs << "<?xml version=\"1.0\" ?>" << endl;
	ofs << "<opencv_storage>" << endl;
	ofs << "<" << Name <<" type_id=\"opencv-haar-classifier\">" << endl;

	//! Exports the cascade
	ExportCascade(ofs,Classifier);

	//! Close the XML header
	ofs << "</" << Name <<">" << endl;
	ofs << "</opencv_storage>" << endl;

	//! Close the file
	ofs.close();
}

void Evolutive::CXMLOpenCV::ExportCascade(fstream &ofs,CCascade *Cascade)
{
	CvSize Size;
	register int i;
	CAdditiveClassEnsemble *StageClass=NULL;
	string ExpectedClass="CCascade";

	// Verify the classifier
	if(!Cascade)
		throw CEvolutiveLibException("NULL pointer",__FILE__,__LINE__,"ExportCascade");

	// Verify the type of the class
	if(ExpectedClass.compare(Cascade->GetClassNameID()))
		throw CEvolutiveLibException("Incorrect class type",__FILE__,__LINE__,"ExportCascade");


	// Retrieve the size
	Size=Cascade->GetSize();
	ofs << "<size>" << Size.width << " " << Size.height << "</size>" << endl;

	// Open the stages tag
	ofs << "<stages>" << endl;

	// Export the stages
	for(i=0;i<Cascade->GetNumClassifiers();i++)
	{
		// Point to the stage classifier
		StageClass=(CAdditiveClassEnsemble*)Cascade->GetClassifier(i);

		// Open the section
		ofs << "<_>" << endl;

		// Write the section header
		ofs << "<!--  stage " << i << "   -->" << endl;

		// Export the stage
		ExportEnsemble(ofs,StageClass);

		// Write the stage threshold
		ofs << "<stage_threshold>";
		PrintDouble(ofs,Cascade->GetStageThr(i));
		ofs << "</stage_threshold>" << endl;

		// Write the parent node and child node
		ofs << "<parent>" << i-1 << "</parent>" << endl;
		ofs << "<next>" << -1 << "</next>" << endl;

		// Close the section
		ofs << "</_>" << endl;
	}

	// close the stages tag
	ofs << "</stages>" << endl;
}

void Evolutive::CXMLOpenCV::ExportEnsemble(fstream &ofs,CAdditiveClassEnsemble *Stage)
{	
	register int i;
	string ExpectedClass="CAdditiveClassEnsemble";

	//! Verify the classifier
	if(!Stage)
		throw CEvolutiveLibException("NULL pointer",__FILE__,__LINE__,"ExportEnsemble");

	//! Verify the type of the class
	if(ExpectedClass.compare(Stage->GetClassNameID()))
		throw CEvolutiveLibException("Incorrect class type",__FILE__,__LINE__,"ExportEnsemble");

	//! Open the trees section
	ofs << "<trees>" << endl;

	for(i=0;i<Stage->GetNumClassifiers();i++)
	{
		// Create the opening tags
		ofs << "<_>" << endl;
		ofs << "<!--  tree " << i << "  -->" << endl;
		ofs << "<_>" << endl;
		ofs << "<!--  root node  -->" << endl;

		// Export the classifier
		ExportThrClassifier(ofs,(CThrClassifier*)Stage->GetClassifier(i));

		// Export the return values
		// Value < threshold
		ofs << "<left_val>";
		PrintDouble(ofs,(-1)*Stage->GetWeight(i));
		ofs << "</left_val>" << endl;

		// Value > threshold
		ofs << "<right_val>";
		PrintDouble(ofs,Stage->GetWeight(i));
		ofs << "</right_val>" << endl;

		//! Create the closing tags
		ofs << "</_>" << endl;
		ofs << "</_>" << endl;
	}

	//! Close the trees section
	ofs << "</trees>" << endl;
}

void Evolutive::CXMLOpenCV::ExportThrClassifier(fstream &ofs,CThrClassifier *Classifier)
{
	CDissociatedDipole *Dipole;
	string ExpectedClass="CThrClassifier";

	//! Verify the classifier
	if(!Classifier)
		throw CEvolutiveLibException("NULL pointer",__FILE__,__LINE__,"ExportThrClassifier");

	//! Verify the type of the class
	if(ExpectedClass.compare(Classifier->GetClassNameID()))
		throw CEvolutiveLibException("Incorrect class type",__FILE__,__LINE__,"ExportThrClassifier");

	//! Retrieve the dipole
	Dipole=(CDissociatedDipole*)Classifier->GetFeature();

	//! Exports the feature data
	ExportDipole(ofs,Dipole);

	//! Export the threshold value
	ofs << "<threshold>";
	PrintDouble(ofs,Classifier->GetThreshold());
	ofs << "</threshold>" << endl;
}

void Evolutive::CXMLOpenCV::ExportDipole(fstream &ofs,CDissociatedDipole *Dipole)
{
	char Buffer[1024];
	register int i;
	int NumRegions;
	CDipoleStruct *DipolData;
	string ExpectedClass="CDissociatedDipole";

	//! Verify the classifier
	if(!Dipole)
		throw CEvolutiveLibException("NULL pointer",__FILE__,__LINE__,"ExportDipole");

	//! Verify the type of the class
	if(ExpectedClass.compare(Dipole->GetClassNameID()))
		throw CEvolutiveLibException("Incorrect class type",__FILE__,__LINE__,"ExportDipole");

	//! Obtain the feature data
	DipolData=Dipole->GetData(NumRegions);

	//! Open the feature tag
	ofs << "<feature>" << endl;

	//! Open the regions tag
	ofs << "<rects>" << endl;

	//! Add the regions information
	for(i=0;i<NumRegions;i++)
	{
		//! Open the data tag
		ofs << "<_>";

		//! Adds the position and size		
		//_itoa_s(DipolData[i].Region.x,Buffer,1024,10);
		sprintf(Buffer,"%d",DipolData[i].Region.x);
		ofs << Buffer << " ";		
		
		//_itoa_s(DipolData[i].Region.y,Buffer,1024,10);
		sprintf(Buffer,"%d",DipolData[i].Region.y);
		ofs << Buffer << " ";		

		//_itoa_s(DipolData[i].Region.width,Buffer,1024,10); 
		sprintf(Buffer,"%d",DipolData[i].Region.width);
		ofs << Buffer << " ";		

		//_itoa_s(DipolData[i].Region.height,Buffer,1024,10);
		sprintf(Buffer,"%d",DipolData[i].Region.height);
		ofs << Buffer << " ";		

		//! Adds the weight
		//sprintf_s(Buffer,1024,"%d.",DipolData[i].Weight);
		sprintf(Buffer,"%d.",DipolData[i].Weight);
		ofs << Buffer;		

		//! Close the data tag
		ofs << "</_>" << endl;
	}
  
	//! Close the regions tag
	ofs << "</rects>" << endl;

	//! Add the rotation information
	ofs << "<tilted>0</tilted>" << endl;

	//! Close the feature tag
	ofs << "</feature>" << endl;
}

void Evolutive::CXMLOpenCV::PrintDouble(fstream &ofs,double Value)
{
	char Buffer[25];

	sprintf(Buffer,"%f",Value);

	ofs << Buffer;
}
#endif //USE_OPENCV